#include <sys/epoll.h>
#include <iostream>
#include <string>
#include <algorithm>
#include "Socket.hpp"

class EpollServer
{
    static const int n = 64;

public:
    EpollServer(int port)
        : _port(port)
    {
    }

    ~EpollServer()
    {
    }

    void Init()
    {
        //创建监听套接字
        _listen_sock.Sock();
        _listen_sock.Bind(_port);
        _listen_sock.Listen();
        //将监听套接字加入epoll模型
        _epfd = epoll_create(128);
        struct epoll_event event;
        event.events = EPOLLIN;
        event.data.fd = _listen_sock.Fd();
        epoll_ctl(_epfd, EPOLL_CTL_ADD, _listen_sock.Fd(), &event);
    }
    
    void Accpter()
    {
        std::string peerip;
        uint16_t peerport;
        int newfd = _listen_sock.Accept(&peerip, &peerport);
        struct epoll_event event;
        event.events = EPOLLIN;
        event.data.fd = newfd;
        epoll_ctl(_epfd, EPOLL_CTL_ADD, newfd, &event);
        std::cout << "get a new link, ip: " << peerip << ", port: " << peerport \
            << ", fd: " << newfd << std::endl;
    }

    void Recver(int fd)
    {
        char buff[1024] = { 0 };
        ssize_t n = read(fd, buff, sizeof(buff) - 1);
        if(n > 0) {
            buff[n] = 0;
            std::cout << "echo# " << buff << std::endl;
        }
        else if(n == 0) {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            std::cout << "close, fd: " << fd << std::endl;
        }
        else {
            std::cerr << "read err" << std::endl;
        }
    }

    void Dispacher(int cnt)
    {
        for (int i = 0; i < cnt; ++i)
        {
            if (_events[i].data.fd == _listen_sock.Fd()) {
                Accpter();
            }
            else {
                Recver(_events[i].data.fd);
            }
        }
    }

    void Run()
    {
        while (true)
        {
            int ret = epoll_wait(_epfd, _events, n, 2000);
            if (ret < 0)
            {
                std::cerr << "epoll_wait err" << std::endl;
                exit(1);
            }
            else if (ret == 0) {
                std::cerr << "time out" << std::endl;
            } //事件派发
            else {
                Dispacher(ret);
            }
        }
    }

private:
    int _epfd;
    int _port;
    Socket _listen_sock;
    struct epoll_event _events[n];
};